#include <stm32f4xx_gpio.h>
#include <misc.h>
#include <rthw.h>
#include "./stm32_drv_can.h"

struct stm_baud_rate_tab
{
    CAN_Baud_enum baud_rate; //波特率
    uint8_t CAN_SJW;
    uint8_t CAN_BS1;
    uint8_t CAN_BS2;
    uint16_t pre; //分频系数
};

//波特率定义
static const struct stm_baud_rate_tab bxcan_baud_rate_tab[] =
    {
        // 42 M
        {CAN1MBaud, CAN_SJW_1tq, CAN_BS1_10tq, CAN_BS2_3tq, 3},
        {CAN800kBaud, CAN_SJW_1tq, CAN_BS1_10tq, CAN_BS2_2tq, 4},
        {CAN500kBaud, CAN_SJW_1tq, CAN_BS1_10tq, CAN_BS2_3tq, 6},
        {CAN250kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 12},
        {CAN125kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 24},
        {CAN100kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 30},
        {CAN50kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 60},
        {CAN20kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 150},
        {CAN10kBaud, CAN_SJW_1tq, CAN_BS1_11tq, CAN_BS2_2tq, 300},
};

static uint8_t get_baud_index(CAN_Baud_enum baud_rate);

uint8_t get_baud_index(CAN_Baud_enum baud_rate)
{
    uint8_t len, index;

    len = sizeof(bxcan_baud_rate_tab) / sizeof(bxcan_baud_rate_tab[0]);

    for (index = 0; index < len; index++)
    {
        if (bxcan_baud_rate_tab[index].baud_rate == baud_rate)
            return index;
    }

    return 0; //未找到，使用默认波特率
}

#define MESSAGE_SIZE_MAX 20 /* 消息队列最大数目 */

/* CAN设备结构体 */
struct can_dev
{
    CAN_TypeDef *can;           /* CAN通道 */
    struct rt_semaphore tx_sem; /* 发送信号量 */

    struct rt_messagequeue tx_data_message; /* 发送消息队列 */
    ALIGN(RT_ALIGN_SIZE)
    char tx_data_message_pool[(sizeof(CanTxMsg) + 4) * MESSAGE_SIZE_MAX]; /* CAN消息队列内存，数据大小+消息头指针 */

    struct rt_thread send_thread; /* 发送线程句柄 */
    ALIGN(RT_ALIGN_SIZE)          /* 线程栈4字节对齐 */
    char send_thread_stack[256];  /* 线程栈起始地址 */

    rt_mq_t rx0_message[7], rx1_message[7];        /* RX0,RX1的14个筛选器,工作在32位标识符列表模式 */
    rt_uint8_t filter_rx0_index, filter_rx1_index; /* 用于指示已使用的筛选器 */
};

static struct can_dev can1 = {
    .can = CAN1,
    .rx0_message = {RT_NULL},
    .rx1_message = {RT_NULL},
    .filter_rx0_index = 0,
    .filter_rx1_index = 0,
};
static struct can_dev can2 = {
    .can = CAN2,
    .rx0_message = {RT_NULL},
    .rx1_message = {RT_NULL},
    .filter_rx0_index = 0,
    .filter_rx1_index = 0,
};

static void CAN_Send_Thread(void *parameter); /* CAN发送线程 */

/* 配置Can接口，配置滤波器 */
void Can_Init(const CAN_TypeDef *CANx, const CAN_Baud_enum baud)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    if (CAN1 == CANx)
    {
        /* CAN1 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
        GPIO_Init(GPIOD, &GPIO_InitStructure);

        GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);
        GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);

        rt_sem_init(&can1.tx_sem, "can1 tx sem", 3, RT_IPC_FLAG_FIFO); /* CAN1发送信号量 */
                                                                       /* CAN1发送数据队列 */
        rt_mq_init(&can1.tx_data_message, "can1 tx message", can1.tx_data_message_pool,
                   sizeof(CanTxMsg), sizeof(can1.tx_data_message_pool), RT_IPC_FLAG_FIFO);
    }
    else if (CAN2 == CANx)
    {
        /* CAN2 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_CAN2);
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_CAN2);

        rt_sem_init(&can2.tx_sem, "can2 tx sem", 3, RT_IPC_FLAG_FIFO); /* CAN2发送信号量 */

        /* CAN2发送数据队列 */
        rt_mq_init(&can2.tx_data_message, "can2 tx message", can2.tx_data_message_pool,
                   sizeof(CanTxMsg), sizeof(can2.tx_data_message_pool), RT_IPC_FLAG_FIFO);
    }

    rt_err_t rt_result = RT_EOK;
    CAN_InitTypeDef CAN_InitStructure;

    uint8_t index = get_baud_index(baud);

    CAN_InitStructure.CAN_TTCM = DISABLE;         /* 非时间触发通信 */
    CAN_InitStructure.CAN_ABOM = ENABLE;          /* 总线关闭后自动启动恢复序列 */
    CAN_InitStructure.CAN_AWUM = DISABLE;         /* 关闭自动唤醒睡眠模式 */
    CAN_InitStructure.CAN_NART = DISABLE;         /* 使能硬件自动重发 */
    CAN_InitStructure.CAN_RFLM = DISABLE;         /* 报文不锁定，新的覆盖旧的 */
    CAN_InitStructure.CAN_TXFP = ENABLE;          /* 优先级由时间决定 */
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; /* 正常模式 */
    CAN_InitStructure.CAN_SJW = bxcan_baud_rate_tab[index].CAN_SJW;
    CAN_InitStructure.CAN_BS1 = bxcan_baud_rate_tab[index].CAN_BS1;
    CAN_InitStructure.CAN_BS2 = bxcan_baud_rate_tab[index].CAN_BS2;
    CAN_InitStructure.CAN_Prescaler = bxcan_baud_rate_tab[index].pre;

    if (CAN1 == CANx)
    {
        CAN_Init(CAN1, &CAN_InitStructure); /* 初始化CAN1 */

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        // NVIC_InitStructure.NVIC_IRQChannel = CAN1_SCE_IRQn;
        // NVIC_Init(&NVIC_InitStructure);

        rt_result = rt_thread_init(&can1.send_thread, "can1 send thread", CAN_Send_Thread, &can1, can1.send_thread_stack, sizeof(can1.send_thread_stack), 4, 2); /* CAN1发送控制线程初始化 */
        if (rt_result == RT_EOK)
        {
            rt_thread_startup(&can1.send_thread); /* 启动线程 */
        }
        else
        {
            rt_kprintf("can1 send thread error\n");
        }
    }
    else if (CAN2 == CANx)
    {
        CAN_Init(CAN2, &CAN_InitStructure); /* 初始化CAN2 */

        NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX1_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = CAN2_TX_IRQn;
        NVIC_Init(&NVIC_InitStructure);
        // NVIC_InitStructure.NVIC_IRQChannel = CAN2_SCE_IRQn;
        // NVIC_Init(&NVIC_InitStructure);

        rt_result = rt_thread_init(&can2.send_thread, "can2 send thread", CAN_Send_Thread, &can2, can2.send_thread_stack, sizeof(can2.send_thread_stack), 4, 4); /* CAN2发送控制线程初始化 */
        if (rt_result == RT_EOK)
        {
            rt_thread_startup(&can2.send_thread); /* 启动线程 */
        }
        else
        {
            rt_kprintf("can2 send thread error\n");
        }
    }
}

/* 通过CANx发送数据，返回发送邮箱 */
rt_err_t Can_Send(CAN_TypeDef *const CANx, const char *buf, const uint8_t length, uint32_t id)
{
    rt_err_t rt_result = RT_EOK;
    CanTxMsg tx_buf;

    tx_buf.StdId = id;            // 标准标识符为 0
    tx_buf.ExtId = id;            // 设置扩展标示符（29 位）
    tx_buf.IDE = CAN_Id_Standard; // 使用标准帧
    tx_buf.RTR = CAN_RTR_Data;    // 消息类型为数据帧，一帧 8 位
    tx_buf.DLC = length;          // 发送数据长度
    for (int i = 0; i < length; i++)
        tx_buf.Data[i] = buf[i]; // 第一帧信息

    struct can_dev *dev = RT_NULL;
    if (CAN1 == CANx)
    {
        dev = &can1;
    }
    else if (CAN2 == CANx)
    {
        dev = &can2;
    }
    else
    {
        return -RT_ERROR;
    }

    rt_result = rt_mq_send(&dev->tx_data_message, &tx_buf, sizeof(CanTxMsg)); /* 将数据存入邮箱 */

    return rt_result;
}

/* 设置滤波器和对应的接收数据邮箱 */
rt_err_t Can_Set_Filter(CAN_TypeDef *CANx, const uint16_t id, rt_mq_t rx_message)
{
    CAN_FilterInitTypeDef CAN_FilterInitStructure;

    uint8_t *rx0_index = RT_NULL, *rx1_index = RT_NULL;
    rt_mq_t *rx0_message = RT_NULL, *rx1_message = RT_NULL;

    uint16_t filter_FIFO_assignment = 0;
    uint8_t filter_number = 0;

    rt_enter_critical(); /* 进入临界区 */

    if (CAN1 == CANx)
    {
        rx0_message = can1.rx0_message;
        rx1_message = can1.rx1_message;
        rx0_index = &can1.filter_rx0_index;
        rx1_index = &can1.filter_rx1_index;
        filter_number = (*rx0_index) + (*rx1_index);
    }
    else if (CAN2 == CANx)
    {
        rx0_message = can2.rx0_message;
        rx1_message = can2.rx1_message;
        rx0_index = &can2.filter_rx0_index;
        rx1_index = &can2.filter_rx1_index;
        filter_number = (*rx0_index) + (*rx1_index) + 14; /* CAN2的筛选器起始是14 */
    }
    else
    {
        rt_exit_critical(); /* 离开临界区 */
        return -RT_ERROR;
    }

    if ((*rx0_index > 6) && (*rx1_index > 6))
    {
        rt_exit_critical(); /* 离开临界区 */
        return -RT_ERROR;   /* 表示筛选器已用完 */
    }

    if ((*rx0_index) > (*rx1_index))
    {
        /* FIFO0 大于 FIFO1，使用FIFO1 */
        filter_FIFO_assignment = CAN_Filter_FIFO1;
        rx1_message[*rx1_index] = rx_message;
        (*rx1_index)++;
        CAN_ITConfig(CANx, CAN_IT_FMP1, DISABLE); //关闭FIFO1接收中断
    }
    else
    {
        /* FIFO1 大于等于 FIFO0，使用FIFO0 */
        filter_FIFO_assignment = CAN_Filter_FIFO0;
        rx0_message[*rx0_index] = rx_message;
        (*rx0_index)++;
        CAN_ITConfig(CANx, CAN_IT_FMP0, DISABLE); //关闭FIFO0接收中断
    }

    CAN_FilterInitStructure.CAN_FilterNumber = filter_number;        /* 过滤器编号 */
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;  /* 标识符掩码模式 */
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; /* 32位筛选器 */

    uint32_t filter_id = 0, mask_id = 0;
    filter_id = (((0x07FFF & id) << 21) | (0 << 2) | (0 << 1)); /* 标准标识符，数据帧 */
    mask_id = ((0x07FFF << 21) | (1 << 2) | (1 << 1));          /* 每一位都必须匹配 */

    CAN_FilterInitStructure.CAN_FilterIdHigh = filter_id >> 16;
    CAN_FilterInitStructure.CAN_FilterIdLow = filter_id & 0xFFFF;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = mask_id >> 16;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = mask_id & 0xFFFF;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = filter_FIFO_assignment;
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; /* 激活过滤器 */
    CAN_FilterInit(&CAN_FilterInitStructure);              /* 滤波器初始化 */

    if (CAN_Filter_FIFO1 == filter_FIFO_assignment)
    {
        CAN_ITConfig(CANx, CAN_IT_FMP1, ENABLE); //使能FIFO1接收中断
    }
    else
    {
        CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE); //使能FIFO0接收中断
    }

    rt_exit_critical(); /* 离开临界区 */
    return RT_EOK;
}

void CAN_Send_Thread(void *parameter)
{
    rt_err_t rt_result = RT_EOK;
    CanTxMsg tx_msg;

    struct can_dev *can = (struct can_dev *)parameter;
    RT_ASSERT(can != RT_NULL);

    CAN_ITConfig(can->can, CAN_IT_TME, ENABLE); /* CAN发送中断允许 */

    while (1)
    {
        rt_result = rt_sem_take(&can->tx_sem, RT_WAITING_FOREVER); /* 获取发送邮箱 */
        if (RT_EOK != rt_result)
        {
            continue;
        }
        rt_result = rt_mq_recv(&can->tx_data_message, &tx_msg, sizeof(CanTxMsg), RT_WAITING_FOREVER); /* 获取待发送数据 */

        CAN_Transmit(can->can, &tx_msg);
    }
}

void CAN1_TX_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();

    if (CAN1->TSR & (CAN_TSR_RQCP0))
    {
        /* 邮箱0发送中断 */
        CAN1->TSR = CAN_TSR_RQCP0;    /* 清空中断标志 */
        rt_sem_release(&can1.tx_sem); /* 释放信号量 */
    }

    if (CAN1->TSR & (CAN_TSR_RQCP1))
    {
        /* 邮箱1发送中断 */
        CAN1->TSR = CAN_TSR_RQCP1;    /* 清空中断标志 */
        rt_sem_release(&can1.tx_sem); /* 释放信号量 */
    }

    if (CAN1->TSR & (CAN_TSR_RQCP2))
    {
        /* 邮箱2发送中断 */
        CAN1->TSR = CAN_TSR_RQCP2;    /* 清空中断标志 */
        rt_sem_release(&can1.tx_sem); /* 释放信号量 */
    }

    /* leave interrupt */
    rt_interrupt_leave();
}
void CAN1_RX0_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();
    if (CAN1->RF0R & 0x03)
    {
        /* 接收到了消息 */
        static CanRxMsg rx;
        /*读取数据*/
        CAN_Receive(CAN1, CAN_FIFO0, &rx);
        /*获取筛选器组*/
        uint8_t filter_number = rx.FMI;
        if (can1.rx0_message[filter_number] != RT_NULL)
        {
            rt_mq_send(can1.rx0_message[filter_number], &rx, sizeof(CanRxMsg));
        }
    }
    /* leave interrupt */
    rt_interrupt_leave();
}

void CAN1_RX1_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();
    if (CAN1->RF1R & 0x03)
    {
        /* 接收到了消息 */
        static CanRxMsg rx;
        /*读取数据*/
        CAN_Receive(CAN1, CAN_FIFO1, &rx);
        /*获取筛选器组*/
        uint8_t filter_number = rx.FMI;
        if (can1.rx1_message[filter_number] != RT_NULL)
        {
            rt_mq_send(can1.rx1_message[filter_number], &rx, sizeof(CanRxMsg));
        }
    }
    /* leave interrupt */
    rt_interrupt_leave();
}

void CAN2_TX_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();

    if (CAN2->TSR & (CAN_TSR_RQCP0))
    {
        /* 邮箱0发送中断 */
        CAN2->TSR = CAN_TSR_RQCP0;    /* 清空中断标志 */
        rt_sem_release(&can2.tx_sem); /* 释放信号量 */
    }

    if (CAN2->TSR & (CAN_TSR_RQCP1))
    {
        /* 邮箱1发送中断 */
        CAN2->TSR = CAN_TSR_RQCP1;    /* 清空中断标志 */
        rt_sem_release(&can2.tx_sem); /* 释放信号量 */
    }

    if (CAN2->TSR & (CAN_TSR_RQCP2))
    {
        /* 邮箱2发送中断 */
        CAN2->TSR = CAN_TSR_RQCP2;    /* 清空中断标志 */
        rt_sem_release(&can2.tx_sem); /* 释放信号量 */
    }

    /* leave interrupt */
    rt_interrupt_leave();
}
void CAN2_RX0_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();
    if (CAN2->RF0R & 0x03)
    {
        /* 接收到了消息 */
        static CanRxMsg rx;
        /*读取数据*/
        CAN_Receive(CAN2, CAN_FIFO0, &rx);

        /*获取筛选器组*/
        uint8_t filter_number = rx.FMI;
        if (can2.rx0_message[filter_number] != RT_NULL)
        {
            rt_mq_send(can2.rx0_message[filter_number], &rx, sizeof(CanRxMsg));
        }
    }
    /* leave interrupt */
    rt_interrupt_leave();
}

void CAN2_RX1_IRQHandler()
{
    /* enter interrupt */
    rt_interrupt_enter();
    if (CAN2->RF1R & 0x03)
    {
        /* 接收到了消息 */
        static CanRxMsg rx;
        /*读取数据*/
        CAN_Receive(CAN2, CAN_FIFO1, &rx);

        /*获取筛选器组*/
        uint8_t filter_number = rx.FMI;
        if (can2.rx1_message[filter_number] != RT_NULL)
        {
            rt_mq_send(can2.rx1_message[filter_number], &rx, sizeof(CanRxMsg));
        }
    }
    /* leave interrupt */
    rt_interrupt_leave();
}
